/*
 * This file is part of the Frequent Passenger Service System 
 * which was created by China Southern Airlines Hunan Branch
 * All Rights Reserved, Any organization or individual <b>must not</b>
 * modify or re-distribute all of or part of the software at any form without permission.
 *
 * IT Department of Hunan Branch, China Southern Airlines, Ltd.
 * 
 * Author:Yi Can yican@cs-air.com alva.yi@gmail.com
 *	
 * Version: $Id$
 */
package com.redhat.redwork.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Translator Chinese Character to PinYin
 * a single Chinese Charater will get multi pinyin returned
 * as for the special situation of Chinese Surname, a extra
 * index file should be build for the chinese name convert
 * @author alva alva.yi@gmail.com yican@csair.com
 *
 */
public class GBKMultiPinyin {
	protected static Map<Character, String[]> dictionary;
	private static GBKMultiPinyin instance = null;
	/**
	 * get a singleon Pinyin Transformer Util
	 * load the default Dictionary
	 * @return
	 */
	public static GBKMultiPinyin getInstance() {
		if (instance == null) {
			instance = new GBKMultiPinyin(GBKMultiPinyin.class
					.getResourceAsStream("GBKMultiPinyin.dat"));
		}
		return instance;
	}

	public GBKMultiPinyin(InputStream dicData) {
		try {
			init(dicData);
		} catch (IOException e) {
			System.err.println("Can't init the dictionary.");
			e.printStackTrace();
		}
	}
	/**
	 * Initialize the Chinese <-> Pinyin database to a hashMap
	 * @param dicData
	 * @throws IOException 
	 */
	private void init(InputStream dicData) throws IOException {
		//init just once, this will save a lot of time
		if(GBKMultiPinyin.dictionary == null) {
			GBKMultiPinyin.dictionary = new HashMap<Character, String[]>();
			//using GBK as the Pinyin dictionary data
			BufferedReader bfRd = new BufferedReader(new InputStreamReader(dicData, "GBK"));
			String line;
			while((line = bfRd.readLine()) != null) {
				int seprator = line.indexOf(":");
				if(seprator != -1) {
					String pinyin = line.substring(seprator + 1).trim().toUpperCase();
					String[] pys = pinyin.split(",");
					//get the key
					Character key = line.substring(0, seprator).trim().charAt(0);
					GBKMultiPinyin.dictionary.put(key, pys);
				}
			}
		}
	}
	/**
	 * get Pinyin of the given single character
	 * if the character have more than one Pinyin
	 * The Set length will greater than 1
	 * @param character
	 * @return
	 */
	private String[] getPinyinForSingleChar(char singleChar) {
		String[] rt = dictionary.get(singleChar);
		if(rt == null) {
			System.err.println("can't convert character:" + singleChar
					+ " please specify a larger dictionary.");
			return new String[]{""};//return a blank
		}
		return rt;
	}
	/**
	 * get the extra Pinyin for the special character
	 * an extra index Map is required for this function for getting correct chinese
	 * @param word
	 * @param index - the extra mapping index for the multi pinyin
	 * @return
	 */
	public String getPinyin(String word, final Map<String, Integer> index, String separator) {
		StringBuilder sb = new StringBuilder();
		int sz = word.length();
		for (int i = 0; i < sz; i++) {
			String[] pinyins = getPinyinForSingleChar(word.charAt(i));
			String key = String.valueOf(word.charAt(i));
			if (index != null && index.containsKey(key)) {
				sb.append( pinyins[index.get(key)] );
			} else {
				sb.append( pinyins[0] );
			}
			if (separator != null && !"".equals(separator) && i < sz - 1) {
				sb.append(separator);
			}
		}
		return sb.toString();
	}
	/**
	 * override method
	 * @param word
	 * @param index
	 * @return
	 */
	public String getPinyin(String word, final Map<String, Integer> index) {
		return getPinyin(word, index, "");
	}
	/**
	 * get Serval combination of Pinyin of the given words
	 * @param word
	 * @return
	 */
	public String[] getPinyin(String word) {
		List<StringBuffer> temp = new ArrayList<StringBuffer>();
		StringBuffer sb = new StringBuffer();
		temp.add(sb);
		if(word != null) {
			for(int i = 0; i < word.length(); i++) {
				char ch = word.charAt(i);
				//System.out.println((int)ch);
				if(ch > 256) {
					String[] pys = getPinyinForSingleChar(ch);
					if(pys.length > 1) {//multi pinyin
						int count = 0;
						int foreSize = temp.size();//should get size here
						//copy the current status
						for(int m = 1; m < pys.length; m++) {
							for(int j = 0; j < foreSize; j++) {
								StringBuffer add = new StringBuffer(temp.get(j));
								temp.add(add);//capacity changed
							}
						}
						for(String s : pys) {	
							//add for a group
							for(int j = 0 + count*foreSize; j < (count+1)*foreSize; j++) {	
								temp.get(j).append(s);//change the internal StringBuffer
							}
							count++;//add the counter
						}
					} else {
						for(StringBuffer tmpSb : temp) {
							tmpSb.append(pys[0]);//single ASCII
						}
					}
				} else {//simple, just add
					for(StringBuffer tmpSb : temp) {
						tmpSb.append(ch);//single ASCII
					}
				}
			}
		}
		//transform to String
		String[] result = new String[temp.size()];
		for(int i = 0; i < temp.size(); i++) {
			result[i] = temp.get(i).toString();
		}
		return result;//sb.toString();
	}
}
